Access to "growing scroll bar"/ "percentage done gauges" from Hwif ================================================================== This .ZIP contains example source code for running a growbar dialog from Hwif. This readme.txt file explains how the code works. Note: growbar items in dialogs are only possible when these dialogs are OO, ie either in a fully HWIM program, or in a dialog called from Hwif via hOODialog(). Note: the discussion in this file assumes familiarity with the HWIFO variant of HWIF, in which the application defines a .CAT file that starts off by duplicating the contents of HWIF.CAT. Files in this .ZIP ------------------ gbar.img ! built .IMG file readme.txt ! readme file gbar.pr ! TS project file make.bat ! makes GBAR.IMG ! gbar.cat ! incorporates HWIF.CAT growbar.c ! main source code gbar.rss ! resource script gbar.afl ! add file list gbar.pic ! icon How to run GBAR.IMG ------------------- Copy to a top-level \IMG\ directory and run from under RunImg. When finished, press Psion-Esc to exit it. The first dialog in the loop lets you specify the parameters for how the second, growbar, dialog operates. How to build GBAR.IMG --------------------- Copy the files to their own directory, eg \sibosdk\growbar. If needed, copy in a TS.RED file and other helper build files. Type MAKE to "make" GBAR.IMG. (You will need to have a copy of HWIFO.LIB available.) The C_DONEWN items in dialogs ----------------------------- The "growing scrollbar" item in a dialog is defined in the resource file simply as CONTROL { class=C_DONEWN; } Compare eg the definition of a numeric editor CONTROL { class=C_NCEDIT; prompt="Total number of loops"; info=NCEDIT { high=100; low=1; }; } The differences are * there is no prompt alongside a growbar * there is no INFO data. When a dialog contains a C_DONEWN element, that element must be sent a WN_SET message, defining the RANGE of the element, before the dialog becomes visible. This is usually done inside the DL_DYN_INIT method of the dialog. Eg from GROWBAR.C: METHOD VOID gbar_dl_dl_dyn_init(PR_DLGBOX *self) { RB_GBAR *prbuf; SE_DONEWN set; prbuf=self->dlgbox.rbuf; set.flags=SE_DONEWN_RANGE; set.range=prbuf->totloops; hDlgSet(1,&set); } The SE_DONEWN struct and the WN_SET method of DONEWN ---------------------------------------------------- typedef struct { UWORD flags; ULONG val; ULONG range; } SE_DONEWN; Flags can contain any combination of SE_DONEWN_RANGE 0x01 SE_DONEWN_VALUE 0x02 SE_DONEWN_INCREMENT 0x04 /* val will be increased by 1 */ SE_DONEWN_INC_VAL 0x08 /* val will be increased by val set */ Thus inside the gbar_update method of the gbar_dl dialog in GROWBAR.C: METHOD VOID gbar_dl_gbar_update(PR_DLGBOX *self) { RB_GBAR *prbuf; SE_DONEWN set; prbuf=self->dlgbox.rbuf; set.flags=SE_DONEWN_VALUE; set.val=prbuf->totloops-prbuf->loopsleft; hDlgSet(1,&set); } Note that the above gbar_update method is not any REPLACEd method but one that has been ADDed by the definition of GBAR_DL to the set defined by the superclass DLGBOX. Complication: who calls the "update" method of the dialog? ---------------------------------------------------------- The "update" method of the dialog has to be called every so often, during the course of the activity being described in the dialog. However, this activity has to take place in between * the dialog starting * the dialog exiting and therefore has to take place inside the ao_run method of a so-called "active object". In the GROWBAR.C example, this activity is simulated by simply calling p_sleep(5) to pause the application for half a second. Thus the code for the ao_run method is METHOD INT bar_ao_ao_run(PR_BAR_AO *self) { RB_GBAR *prb; p_sleep(5); /* the next stage of computation or drawing etc */ p_send2(self,O_AO_QUEUE); prb=self->bar_ao.prb; if (!--(prb->loopsleft)) { p_send2(DatDialogPtr,O_DESTROY); prb->exit_code=0; } else if (!--(prb->toupdate)) { p_send2(DatDialogPtr,O_GBAR_UPDATE); prb->toupdate=prb->update; } return(RUN_ACTIVE_USED); } Note the following points: 1. the next stage of the "computation" is, for convenience, *always* queued (by means of the call to ao_queue) 2. thus the growbar dialog itself can be called by the code p_send2(ao,O_AO_QUEUE); doDial(C_GBAR_DL,DL_GBAR,&gb_data); p_send2(ao,O_AO_CANCEL); when the active object is always cancelled when the dialog completes 3. if the computation is finished, the active object sends a DESTROY message to DatDialogPtr 4. otherwise, every so often, the active object sends an "update" message to DatDialogPtr 5. clearly, the handle of the current dialog is always accessible from the "reserved static" DatDialogPtr 6. don't forget to return(RUN_ACTIVE_USED) from your ao_run method (on pain of being panicked 143, most likely) 7. in this example, there are no parameters to the "update" message, but in another example there might be. The basic point to bear in mind ------------------------------- The growbar dialog can terminate in general in either of two ways: * the user presses Esc - in which case the code falls out of the bottom of hOODialog without the cooperation of any of your code in the ao_run method * the computation finishes - in which case you send the dialog the destroy message and precipitate the completion of the hOODialog call. Other comments on GROWBAR.C --------------------------- Help has to be disallowed in the growbar dialog, to avoid accidents if the growbar dialog gets terminated before the help system is shut down. (These complications only arise for hOODialog, and not for pure HWIM programs.) Hence the "magic" in the WN_SENSE_HELP method. For a similar reason access to the freeform dialler has to be disallowed - hence the "magic" in the routine DisallowDialling(). For simplicity, I have deliberately ignored considering various run-time errors that might arise - eg running out of memory when launching either dialog. In GROWBAR.C, the active object AO is created early in the application, and is used repeatedly each time the growbar dialog is invoked. Another design approach would be to have the active object exist only throughout the lifetime of an individual growbar dialog. Another design decision in GROWBAR is not to access any specific static data from inside either the dialog code or the active object code. Each of these object interacts with the rest of the world only via the "rbuf" pointers. Another design option would be to access more static data from inside these objects. These notes prepared by: ------------------------ David Wood, Psion Product Development, 21st August 1994.